/******************************************************************************
 *                       B O M B E R M A N  2 0 1 2
 * 
 * File Name: Level.java
 * 
 * COP 4331 Summer 2012 Project
 * 
 * Authors: Trevor Mancuso, Chris Chiarella, Zach Hoyler, Daniel Martin
 * 
 * 
 * Description: Generates and validates the level and keeps track of the 
 * entities inside of it.
 * 
 ******************************************************************************/
package bomberman;
import java.util.*;

public class Level {
    //arrays for keeping track of where everything is
    public Barrier[][] barrierArray;
    public int levelSize;
    public Bomb[][] bombArray;
    public Explosion[][] explosionArray;
    public Powerup[][] powerupArray;
    
    //variables for sudden death
    public final int SUDDEN_DEATH_DELAY = 100;
    private int suddenDeathStart, suddenDeathEnd;
    private int nextSuddenDeathX;
    private int nextSuddenDeathY;
    private boolean suddenDeathEnded;
    
    //initialize the level
    Level(int levelSize)
    {
        //set the levelSize and then the arrays at levelSize by levelSize
        this.levelSize = levelSize;
        barrierArray = new Barrier[levelSize][levelSize];
        bombArray = new Bomb[levelSize][levelSize];
        explosionArray = new Explosion[levelSize][levelSize];
        powerupArray = new Powerup[levelSize][levelSize];
        
        //set the sudden death counters and starting location
        suddenDeathStart = 0;
        suddenDeathEnd = Bomberman.getLevelSize() - 1;
        nextSuddenDeathX = 0;
        nextSuddenDeathY = 0;
        suddenDeathEnded = false;
        
        //generate a level
        GenerateLevel();
        while(!ValidLevel(29, 0) && !ValidLevel(29,29)) //check to see if it is valid
        {
            GenerateLevel(); //if not then generate a new level and try again
        }
    }
    
    //return true if the level is valid (all players can get to each other), otherwise return false
    private boolean ValidLevel(int x, int y)
    {
        //create an x and a y stack
        int xStack[] = new int[100];
        int yStack[] = new int[100];
        xStack[0] = 0;
        yStack[0] = 0;
        int stackPointer = 0;
        
        //create a 2d array of the levelSize by levelSize for the visited squares and set them all to false
        boolean visited[][] = new boolean[levelSize][levelSize];
        for(int i = 0; i < levelSize; i++)
            for(int n = 0; n < levelSize; n++)
                visited[i][n] = false;
        visited[0][0] = true; //set the starting square to true
        while(stackPointer > -1 && (xStack[stackPointer] != x && yStack[stackPointer] != y)) //if the last value on the stack hasn't been popped and we aren't at the ending location
        {
            if(xStack[stackPointer] + 1 < 30 && !visited[yStack[stackPointer]][xStack[stackPointer] + 1]) //if the right square hasn't been visited and isn't off the level
            {
                visited[yStack[stackPointer]][xStack[stackPointer] + 1] = true; //set the right square to visited
                
                //if there isn't a barrier, or the barrier that is there is destroyable
                if(barrierArray[yStack[stackPointer]][xStack[stackPointer] + 1] == null || (barrierArray[yStack[stackPointer]][xStack[stackPointer] + 1] != null && barrierArray[yStack[stackPointer]][xStack[stackPointer] + 1].isDestructable()))
                {
                    //increment the stack pointer and add the right square to the x and y stacks
                    stackPointer++;
                    xStack[stackPointer] = xStack[stackPointer - 1] + 1;
                    yStack[stackPointer] = yStack[stackPointer - 1];
                }
            }
            else if(yStack[stackPointer] + 1 < 30 && !visited[yStack[stackPointer] + 1][xStack[stackPointer]]) //if the lower square hasn't been visited and isn't off the level
            {
                visited[yStack[stackPointer] + 1][xStack[stackPointer]] = true; //set the lower square to visited
                
                //if there isn't a barrier, or the barrier that is there is destroyable
                if(barrierArray[yStack[stackPointer] + 1][xStack[stackPointer]] == null || (barrierArray[yStack[stackPointer] + 1][xStack[stackPointer]] != null && barrierArray[yStack[stackPointer] + 1][xStack[stackPointer]].isDestructable()))
                {
                    //increment the stack pointer and add the lower square to the x and y stacks
                    stackPointer++;
                    xStack[stackPointer] = xStack[stackPointer - 1];
                    yStack[stackPointer] = yStack[stackPointer - 1] + 1;
                }
            }
            else if(xStack[stackPointer] - 1 > -1 && !visited[yStack[stackPointer]][xStack[stackPointer] - 1]) //if the left square hasn't been visited and isn't off the level
            {
                visited[yStack[stackPointer]][xStack[stackPointer] - 1] = true; //set the left square to visited
                
                //if there isn't a barrier, or the barrier that is there is destroyable
                if(barrierArray[yStack[stackPointer]][xStack[stackPointer] - 1] == null|| (barrierArray[yStack[stackPointer]][xStack[stackPointer] - 1] != null && barrierArray[yStack[stackPointer]][xStack[stackPointer] - 1].isDestructable()))
                {
                    //increment the stack pointer and add the left square to the x and y stacks
                    stackPointer++;
                    xStack[stackPointer] = xStack[stackPointer - 1] - 1;
                    yStack[stackPointer] = yStack[stackPointer - 1];
                }
            }
            else if(yStack[stackPointer] - 1 > -1 && !visited[yStack[stackPointer] - 1][xStack[stackPointer]])  //if the upper square hasn't been visited and isn't off the level
            {
                visited[yStack[stackPointer] - 1][xStack[stackPointer]] = true; //set the upper square to visited
                
                //if there isn't a barrier, or the barrier that is there is destroyable
                if(barrierArray[yStack[stackPointer] - 1][xStack[stackPointer]] == null || (barrierArray[yStack[stackPointer] - 1][xStack[stackPointer]] != null && barrierArray[yStack[stackPointer] - 1][xStack[stackPointer]].isDestructable()))
                {
                    //increment the stack pointer and add the upper square to the x and y stacks
                    stackPointer++;
                    xStack[stackPointer] = xStack[stackPointer - 1];
                    yStack[stackPointer] = yStack[stackPointer - 1] - 1;
                }
            }
            else //if all the squares are visited or aren't valid
            {
                stackPointer--; //pop the top values from the stacks
            }
        }
        if(stackPointer == - 1) //if the stackPointer is -1 return false (a path wasn't found)
            return false;
        else //otherwise return true
            return true;
    }
    
    //generate the level
    private void GenerateLevel()
    {
        Random rand = new Random(); //create a random
        for(int i = 0; i < levelSize; i++) //go through every square in teh level
        {
            for(int n = 0; n < levelSize; n++)
            {
                int RandomNum = rand.nextInt(100); //generate a number between 0 and 99
                if(RandomNum < 60) //if less than 60 
                    barrierArray[i][n] = new Barrier(); //create a barrier
                else //otherwise make a null barrier
                    barrierArray[i][n] = null; 
            }
        }
        
        //set the starting squares, and the two adjacent squares to null (bomber must have room to start safely)
        barrierArray[0][0] = null;
        barrierArray[0][1] = null;
        barrierArray[1][0] = null;
        barrierArray[levelSize - 1][0] = null;
        barrierArray[levelSize - 1][1] = null;
        barrierArray[levelSize - 2][0] = null;
        barrierArray[0][levelSize - 1] = null;
        barrierArray[0][levelSize - 2] = null;
        barrierArray[1][levelSize - 1] = null;
        barrierArray[levelSize - 1][levelSize - 1] = null;
        barrierArray[levelSize - 1][levelSize - 2] = null;
        barrierArray[levelSize - 2][levelSize - 1] = null;
    }
    
    //return the barrier in a space or null if there isn't one
    public Barrier getBarrier(int x, int y)
    {
        if(x >= 0 && x < levelSize && y >= 0 && y < levelSize) //if checking in the level
            return barrierArray[y][x]; //return the barrier
        else //otherwise return null
            return null;
    }
    
    //return whether there is a bomb in the square or not
    public boolean isBomb(int x, int y)
    {
        if((x >= 0 && x <= 29) && (y >= 0 && y <= 29)) //if checking in the level
            if(bombArray[x][y] != null) //if the bomb array isn't null in that square
                return true; //return true
        return false; //otherwise return false
    }
    
    //return the bomb in a square
    public Bomb getBomb(int x, int y)
    {
        if(x >= 0 && x <= 29 && y >= 0 && y <= 29) //if in the level
            return bombArray[x][y]; //return the bomb located there
        else //otherwise return null
            return null;
    }
    
    //return the explosion in a square
    public Explosion getExplosion(int x, int y)
    {
        return explosionArray[x][y];
    }
    
    //return true if there is a barrier, false if there isn't
    public boolean isBarrier(int x, int y)
    {
        if(x >=0 && y >=0 && x < levelSize && y < levelSize) //if in the level
        {
            if (!(barrierArray[x][y] == null)) //if not a null barrier
                return true; //return true
            else //otherwise return false
                return false;
        }
        return false;
    }
    
    //return the powerup in the square 
    public Powerup getPowerup(int x, int y)
    {
        if(x < 30 && x >= 0 && y < 30 && y >= 0) //if in the level
            return powerupArray[x][y]; //return the powerup
        else //otherwise return null
            return null;
    }
    
    //run the sudden death
    public void suddenDeath(Bomberman game)
    {
        //set the next sudden death square
        int x = nextSuddenDeathX;
        int y = nextSuddenDeathY;
        
        if (!suddenDeathEnded) //if sudden death hasn't ended
        {
            Sound.DEATHBLOCK.play(); //play the death block sounds
            
           //if there is a barrier in the square make it null
            if (barrierArray[y][x] != null)
                barrierArray[y][x] = null;
            
            // if there is a powerup in the square make it null
            if (powerupArray[x][y] != null)
                powerupArray[x][y] = null;
            
            barrierArray[y][x] = new Barrier(false); //make an indestructable barrier
            
            // Kill any bombers in the way
            for (Bomber b : game.bombers)
                if (b != null && b.getX() == x && b.getY() == y)
                    b.kill();

            //if y is at the start spot 
            if (y == suddenDeathStart)
            {
                if (x < suddenDeathEnd) //if x isn't at the end of the line
                    nextSuddenDeathX++; //increment x
                else //othewise increment y
                    nextSuddenDeathY++;
            }
            else if (x == suddenDeathEnd) //if x is at the end of the line
            {
                if (y < suddenDeathEnd) //if y isn't 
                    nextSuddenDeathY++; //increment y
                else //otherwise subtract from x
                    nextSuddenDeathX--;
            }
            else if (y == suddenDeathEnd) //if y is at the end of it's line
            {
                if (x > suddenDeathStart) //if x is greater than the start
                    nextSuddenDeathX--; // subtract from x
                else //otherwise subtract from y
                    nextSuddenDeathY--;

                if (suddenDeathEnd - suddenDeathStart <= 1) //if the end and start are within a space of each other
                    suddenDeathEnded = true; //end sudden death
            }
            else if (x == suddenDeathStart) //if x is at the start
            {
                if (y > suddenDeathStart + 1) //if y is greater than the start plus one
                    nextSuddenDeathY--; //decrement from y
                else //otherwise
                {
                    //update the start and end spaces
                        nextSuddenDeathX++;
                        suddenDeathStart += 1;
                        suddenDeathEnd -= 1;
                }
            }
        }
    }
}